﻿using Nop.Core;
using Nop.Core.Domain.Orders;
using Nop.Core.Domain.Customers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Nop.Core.Domain.Logistics;

namespace Nop.Services.Orders
{
    public interface IInvoiceService
    {
        /// <summary>
        /// Gets an invoice
        /// </summary>
        /// <param name="invoiceId">The invoice identifier</param>
        /// <returns>Invoice</returns>
        Invoice GetInvoiceById(int invoiceId);

        /// <summary>
        /// Get invoices by identifiers
        /// </summary>
        /// <param name="invoiceIds">invoice identifiers</param>
        /// <returns>Invoices</returns>
        IList<Invoice> GetInvoicesByIds(int[] invoiceIds);

        /// <summary>
        /// Get invoices by identifiers
        /// </summary>
        /// <param name="orderIds">invoice identifiers</param>
        /// <param name="showAllStatus">show all status, or only show published</param>
        /// <returns>Invoices</returns>
        IList<Invoice> GetInvoicesByCustomerId(int customerId, bool showAllStatus = false);

        /// <summary>
        /// Gets an invoice
        /// </summary>
        /// <param name="orderGuid">The invoice identifier</param>
        /// <returns>Invoice</returns>
        Invoice GetInvoiceByGuid(Guid invoiceGuid);

        /// <summary>
        /// Gets an invoice
        /// </summary>
        /// <param name="orderGuid">The invoice number</param>
        /// <returns>Invoice</returns>
        Invoice GetInvoiceByNumber(string invoiceNumber);

        /// <summary>
        /// Search invoice
        /// </summary>
        /// <param name="customerId">Invoices related to a user id; null to ignore user id</param>
        /// <param name="startTime">Invoice start time; null to load all invoices</param>
        /// <param name="endTime">Invoice end time; null to load all invoices</param>
        /// <param name="status">Invoice status; null to load all invoices</param>
        /// <param name="email">Customer Email</param>
        /// <param name="billingEmail">Invoice billing emaili; null to load all invoices</param>
        /// <param name="invoiceGuid">Invoice identifier; null to load all invoices</param>
        /// <param name="invoiceNumber">Invoice number; null to load all invoices</param>
        /// <param name="name">The invoice name; null to load all invoices</param>
        /// <param name="orderKind">The order kind; null to load all invoices</param>
        /// <param name="districtId">The district identifier; null to load all invoices</param>
        /// <param name="storeId">Store identifier</param>
        /// <param name="pageIndex">Page index</param>
        /// <param name="pageSize">Page size</param>
        /// <returns>Invoices</returns>
        IPagedList<Invoice> SearchInvoices(int? customerId, DateTime? startTime, DateTime? endTime,
            InvoiceStatus? status, string email, string billingEmail,
            string invoiceGuid, string invoiceNumber, string name, OrderKind? orderKind, int? districtId, int storeId, int pageIndex, int pageSize);

        /// <summary>
        /// Get the total due of the customer
        /// </summary>
        /// <param name="customer">Customer</param>
        /// <returns></returns>
        decimal GetTotalDueByCustomer(Customer customer);

        /// <summary>
        /// Get invoice report
        /// </summary>
        /// <param name="startTime">Invoice start time; null to load all invoices</param>
        /// <param name="endTime">Invoice end time; null to load all invoices</param>
        /// <param name="status">Invoice status; null to load all invoices</param>
        /// <param name="email">Customer Email</param>
        /// <param name="billingEmail">Invoice billing emaili; null to load all invoices</param>
        /// <param name="invoiceGuid">Invoice identifier; null to load all invoices</param>
        /// <param name="invoiceNumber">Invoice number; null to load all invoices</param>
        /// <param name="name">The invoice name; null to load all invoices</param>
        /// <param name="orderKind">The order kind; null to load all invoices</param>
        /// <param name="districtId">The district identifier; null to load all invoices</param>
        /// <param name="storeId">Store identifier</param>
        /// <returns>Invoice report</returns>
        InvoiceReport GetInvoiceReport(DateTime? startTime, DateTime? endTime, InvoiceStatus? status, string email, string billingEmail, string invoiceGuid, string invoiceNumber, string name, OrderKind? orderKind, int? districtId, int storeId);

        /// <summary>
        /// Deletes an invoice
        /// </summary>
        /// <param name="invoice">The invoice</param>
        void DeleteInvoice(Invoice invoice);

        /// <summary>
        /// Inserts an invoice
        /// </summary>
        /// <param name="order">invoice</param>
        void InsertInvoice(Invoice invoice);

        /// <summary>
        /// Updates the invoice
        /// </summary>
        /// <param name="order">The invoice</param>
        void UpdateInvoice(Invoice invoice);

        /// <summary>
        /// Gets the orders' total charge
        /// </summary>
        /// <param name="orders"></param>
        /// <returns></returns>
        InvoiceTotal GetTotalCharge(IEnumerable<Order> orders, int? orderStatus = null, int? shippingStatus = null, int? paymentStatus = null);

        /// <summary>
        /// Create an Invoice given an order
        /// </summary>
        /// <param name="orderId">Order ID</param>
        /// <param name="customer">Customer</param>
        /// <param name="invoiceStatus">Invoice Status</param>
        /// <returns>Invoice</returns>
        Invoice CreateInvoice(int orderId, Customer customer, InvoiceStatus invoiceStatus);

        /// <summary>
        /// Create an Invoice given an order
        /// </summary>
        /// <param name="orderId">order Id</param>
        /// <param name="customer">custer</param>
        /// <param name="invoiceStatus">Invoice Status</param>
        /// <returns>Invoice</returns>
        Invoice CreateSingleInvoice(int orderId, Customer customer, InvoiceStatus invoiceStatus);

        /// <summary>
        /// Create an Invoice given orders
        /// </summary>
        /// <param name="orderIds">Order identifiers for this invoice</param>
        /// <param name="name">Name</param>
        /// <param name="comment">Comment</param>
        /// <param name="customer">Customer</param>
        /// <param name="dueDate">Due date</param>
        /// <param name="invoiceStatus">Invoice Status</param>
        /// <returns>Invoice</returns>
        Invoice CreateInvoice(int[] orderIds, string name, string comment, Customer customer, DateTime dueDate, InvoiceStatus invoiceStatus);

        /// <summary>
        /// Create Invoices per customer by given conditions
        /// </summary>
        /// <param name="startTime">Invoice start time</param>
        /// <param name="endTime">Invoice end time</param>
        /// <param name="DistrictId">The identifier of the district which invoice belongs to</param>
        /// <param name="name">Invoice name</param>
        /// <param name="dueDate">Invoice due date</param>
        /// <param name="orderKind">Order kind of the invoice</param>
        void BulkCreateInvoices(DateTime startTime, DateTime endTime, int DistrictId, string name, DateTime dueDate, OrderKind orderKind);

        /// <summary>
        /// Update related invoice status if order is changed.
        /// </summary>
        /// <param name="order">order</param>
        void UpdateInvoiceStatus(Order order);

        /// <summary>
        /// Get the district associated with the invoice.
        /// </summary>
        /// <param name="invoice">invoice</param>
        /// <returns>district</returns>
        District GetInvoiceDistrict(Invoice invoice);
    }
}
